home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / Common / ZInvariant.h < prev    next >
Text File  |  1997-06-18  |  6KB  |  199 lines

  1. /*
  2.  *  File:       ZInvariant.h
  3.  *  Summary:    Mixin for objects that use PRECONDITION and POSTCONDITION macros.
  4.  *  Written by: Jesse Jones
  5.  *
  6.  *    Abstract:    According to the design by contract design methodology (see _Object
  7.  *                Oriented Software Construction_) clients of an object promise to call
  8.  *                an objects methods with correct arguments and the object promises to
  9.  *                do the right thing when given correct arguments. Since we're trying
  10.  *                to write robust software we'll check to make sure each party lives up
  11.  *                to the contract.
  12.  *
  13.  *                To do this check we use two macros: PRECONDITION and POSTCONDITION.
  14.  *                PRECONDITION is used to check a methods arguments and POSTCONDITION
  15.  *                is used to check that the method did what it's supposed to. Since
  16.  *                objects have state these macros also check to see that the object's
  17.  *                state is still consistent. They do this by calling the Invariant
  18.  *                method. Subclasses should override this and add ASSERTs to verify
  19.  *                that the object is still OK.
  20.  *
  21.  *                Note that these checks should only be done for public methods: while
  22.  *                inside a public method the object may temporarily enter an invalid
  23.  *                state.
  24.  *
  25.  *                In Raven 1.0 the macros looked like this:
  26.  *                    #define    PRECONDITION(x)        this->Invariant(); ASSERT(x);
  27.  *                    #define    POSTCONDITION(x)    this->Invariant(); ASSERT(x);
  28.  *                This was nice and simple, but caused problems when a protected
  29.  *                method called a public functions. If the object happened to be
  30.  *                in an invalid state the Invariant method would fire. When this
  31.  *                happened the easiest fix was simply to replace the PRECONDITION 
  32.  *                and POSTCONDITION checks with an ASSERT. This was obviously not
  33.  *                a good solution.
  34.  *
  35.  *                Raven 1.1 uses a more sophisticated approach that, unfortunately,
  36.  *                requires objects to descend from MInvariant if they wish to use
  37.  *                PRECONDITION and POSTCONDITION. The new macros look like this:
  38.  *                    #define    PRECONDITION(x)        ASSERT(x); ¥
  39.  *                                                const MInvariant* _object = dynamic_cast<const MInvariant*>(this); ¥
  40.  *                                                ASSERT(_object != nil); ¥
  41.  *                                                ZCheckInvariant _check(_object)
  42.  *                    #define    POSTCONDITION(x)    ASSERT(x)
  43.  *                ZCheckInvariant is a stack based class that increments an MInvariants
  44.  *                nesting level and calls the Invariant method if the nesting level is 
  45.  *                one. By doing this the Invariant function is only called at the start 
  46.  *                and end of the original public method. The 'this' pointer is cast to
  47.  *                an MInvariant* to allow PRECONDITION to be used inside a mixin class
  48.  *                (which, of course, requires that the concrete class descend from MInvariant).
  49.  *
  50.  *    Classes:    ZCheckInvariant        - PRECONDITION creates one of these to ensure that
  51.  *                                      the Invariant method is only called at the entry
  52.  *                                      and exit of a function.
  53.  *                TDisableInvariant    - Can be used to disable invariant checks within a block.
  54.  *                MInvariant            - Mixin allowing PRECONDITION and POSTCONDITION macros 
  55.  *                                      to be used.
  56.  *
  57.  *  Copyright ゥ 1997 Jesse Jones. 
  58.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  59.  *
  60.  *  Change History (most recent first):    
  61.  *
  62.  *         <4>     6/14/97    JDJ        Provided an implementation of pure virtual Invariant.
  63.  *         <3>     5/17/97    JDJ        Updated Abstract.
  64.  *         <2>     5/17/97    JDJ        ZCheckInvariant ctor ASSERTs that object is non-nil.
  65.  *         <1>     4/12/97    JDJ        Created.
  66.  */
  67.  
  68. #pragma once
  69.  
  70.  
  71. //-----------------------------------
  72. //    Forward References
  73. //
  74. class MInvariant;
  75. class ZCheckInvariant;
  76.  
  77.  
  78. // ===================================================================================
  79. //    class ZCheckInvariant
  80. // ===================================================================================
  81. #if DEBUG
  82. class ZCheckInvariant {
  83.  
  84. //-----------------------------------
  85. //    Initialization/Destruction
  86. //
  87. public:
  88.                          ~ZCheckInvariant();
  89.                         // Calls Invariant if object's nesting is one and then decrements nesting.
  90.  
  91.                         ZCheckInvariant(const MInvariant* object);
  92.                         // Increments mNesting and calls Invariant if it's one.
  93.  
  94. //-----------------------------------
  95. //    Member Data
  96. //
  97. protected:                    
  98.     const MInvariant*    mObject;
  99. };
  100. #endif
  101.  
  102.  
  103. // ===================================================================================
  104. //    class TDisableInvariant
  105. // ===================================================================================
  106. class TDisableInvariant {
  107.  
  108. //-----------------------------------
  109. //    Initialization/Destruction
  110. //
  111. public:
  112.                          ~TDisableInvariant();
  113.                         // Decrements mNesting.
  114.  
  115.                         TDisableInvariant(const MInvariant* object);
  116.                         // Increments mNesting (so Invariant won't be called).
  117.  
  118. //-----------------------------------
  119. //    Member Data
  120. //
  121. protected:                    
  122. #if DEBUG
  123.     const MInvariant*    mObject;
  124. #endif
  125. };
  126.  
  127.  
  128. // ===================================================================================
  129. //    class MInvariant
  130. // ===================================================================================
  131. class MInvariant {
  132.  
  133.     friend ZCheckInvariant;
  134.     friend TDisableInvariant;
  135.  
  136. //-----------------------------------
  137. //    Initialization/Destruction
  138. //
  139. public:
  140.     virtual             ~MInvariant();
  141.  
  142.                         MInvariant();
  143.  
  144. //-----------------------------------
  145. //    API
  146. //
  147. protected:
  148.     virtual void         Invariant() const = 0;
  149.                         // Override and add ASSERTs to ensure your subclasses member data
  150.                         // are still valid. Note that you should *always* call the
  151.                         // Inherited Invariant.
  152.     
  153. //-----------------------------------
  154. //    Member Data
  155. //
  156. protected:
  157. #if DEBUG
  158.     mutable long    mNesting;
  159. #endif
  160. };
  161.  
  162.  
  163. // ===================================================================================
  164. //    Inlines
  165. // ===================================================================================
  166. #if DEBUG
  167.     inline TDisableInvariant::~TDisableInvariant()        
  168.     {
  169.         mObject->mNesting--;
  170.     }
  171.  
  172.     inline TDisableInvariant::TDisableInvariant(const MInvariant* object)        
  173.     {
  174.         mObject = object; 
  175.         
  176.         mObject->mNesting++;
  177.     }
  178. #else
  179.     inline TDisableInvariant::~TDisableInvariant()        
  180.     {
  181.     }
  182.  
  183.     inline TDisableInvariant::TDisableInvariant(const MInvariant*)        
  184.     {        
  185.     }
  186.  
  187.     inline MInvariant::~MInvariant()            
  188.     {
  189.     }
  190.  
  191.     inline MInvariant::MInvariant()            
  192.     {
  193.     }
  194.  
  195.     inline void MInvariant::Invariant() const
  196.     {
  197.     }
  198. #endif    // DEBUG
  199.